home *** CD-ROM | disk | FTP | other *** search
- /**********************************************************************/
- /* ff.c */
- /* */
- /* Routines for form factor approximation. Algorithms used: */
- /* */
- /* Wallace89 : differential area to disc approximation, with uniform */
- /* or jittered sampling, and adaptive source sampling. */
- /* Change from circle to ellipse approximation, plus add */
- /* in differential to finite approximation for */
- /* perpendicular case */
- /* Baum/Rush90 : analytic ff approximation for special cases: */
- /* 1) Proximity violations. */
- /* 2) Visibility violations. */
- /* 3) PR violations. */
- /* 4) Wallace89 problems. */
- /* Hanrahan91 : BF refinement, and O(n) form-factor interaction */
- /* (not completed in this revision). */
- /* */
- /* Copyright (C) 1992, Bernard Kwok */
- /* All rights reserved. */
- /* Revision 1.0 */
- /* May, 1992 */
- /**********************************************************************/
- #include <stdio.h>
- #include <stdlib.h>
- #include <math.h>
- #include "geo.h"
- #include "misc.h"
- #include "io.h"
- #include "struct.h"
- #include "rad.h"
- #include "ray.h"
- #include "ff.h"
- #include "rtime.h"
-
- /**********************************************************************/
- extern OptionType Option;
- extern char *ProgName;
- extern int HitObject();
- extern Time_Stats tstats;
-
- /**********************************************************************/
- /* Form factor globals */
- /**********************************************************************/
- double MAX_F_DIFF_EDGE = 0.016; /* maximum allowed difference
- between ff of 2 vertices of a
- edge before you have to
- subdivide */
- double MIN_ELEMENT_PERC = 0.1; /* minimum % area of element
- for subdivision */
-
- FF_OptionType FF_Options = { /* Default B, F tolerances and */
- DEFAULT_B_min, DEFAULT_B_max, /* default uniform sampling */
- DEFAULT_F_min, DEFAULT_F_max, /* with default 4x4 sampling */
- UNIFORM, DEFAULT_SAMPLES, /* grid */
- NUMERICAL_FF, /* MIN_ELEMENT_AREA, */
- MAX_F_DIFF_POLY, /* MAX_F_DIFF_EDGE */ 0.016,
- MAX_PATCH_LEVELS, DISC_FF
- };
-
- /**********************************************************************/
- /* Print form factor options */
- /**********************************************************************/
- void ff_print_FF_Options(ffopt)
- FF_OptionType ffopt;
- {
- FILE *fp;
- if (Option.device == PRINT)
- fp = stdout;
- else
- fp = Option.StatFile;
-
- fprintf(fp,"\n\t*** Form-factor options *** \n");
- fprintf(fp,"\tB {max %g} {min %g}\n", ffopt.B_max, ffopt.B_min);
- fprintf(fp,"\tF {max %g} {min %g}\n", ffopt.F_max, ffopt.F_min);
- fprintf(fp,"\t%s %s form factors",
- (ffopt.fftype == ANALYTIC_FF ? "Analytic" : "Numerical"),
- (ffopt.sample_shape == ELLIPSE_FF ? "elliptical" : "circular"));
- if (ffopt.use_analytic) fprintf(fp,", WITH Analytic for special cases.\n");
- else fprintf(fp,".\n");
- fprintf(fp,"\tMinimum subdivision area %g\n", ffopt.min_element_area);
- fprintf(fp,"\tMaximum poly form factor difference %g\n", ffopt.F_diff_poly);
- fprintf(fp,"\tMaximum edge form factor difference %g\n", ffopt.F_diff_edge);
- fprintf(fp,"\tMaximum patch subdivision levels %d\n", ffopt.max_levels);
-
- if (Option.ff_raytrace) {
- fprintf(fp,"\tUsing ray cast visibility testing, with\n");
- fprintf(fp,"\t%s sampling with %d %s samples per polygon.\n",
- (ffopt.sampling_type == UNIFORM ? "uniform" : "jittered"),
- ffopt.num_samples,
- (ffopt.varying_numsamps == 1 ? "adjusted" : "unadjusted"));
- }
- }
-
- /**********************************************************************/
- /* Compute xyz coordinates of a point on quadrilateral given it's u,v */
- /* coordinates using bi-linear mapping */
- /**********************************************************************/
- void UVToXYZ(quad, u, v, xyz)
- Vector quad[MAX_PATCH_VTX];
- double u,v;
- Vector *xyz;
- {
- xyz->x = quad[0].x * (1.-u)*(1.-v) + quad[1].x * (1.-u)*v +
- quad[2].x *u*v + quad[3].x * u*(1.-v);
- xyz->y = quad[0].y * (1.-u)*(1.-v) + quad[1].y * (1.-u)*v +
- quad[2].y *u*v + quad[3].y * u*(1.-v);
- xyz->z = quad[0].z * (1.-u)*(1.-v) + quad[1].z * (1.-u)*v +
- quad[2].z *u*v + quad[3].z * u*(1.-v);
- }
-
- /**********************************************************************/
- /* Initialize the set of samples */
- /**********************************************************************/
- int Init_Samples(s)
- Sampletype s[MAX_SAMPLES];
- {
- int i;
- for(i=0;i<MAX_SAMPLES;i++) { s[i].p = 0; }
- }
-
- /**********************************************************************/
- /* Print set of samples (for testing only) */
- /**********************************************************************/
- void ff_print_samples(s,num_samples,label)
- Sampletype s[MAX_SAMPLES];
- int num_samples;
- char *label;
- {
- int i,j;
-
- printf("\n\tSamples %s (%d) {\n", label, num_samples);
- for(i=0;i<num_samples;i++) {
- printf("\tPoly[%d] %s%d {", i, s[i].p->name, s[i].p->id);
- printf(" Pos %g %g %g;", s[i].pos.x, s[i].pos.y, s[i].pos.z);
- printf(" Norm %g %g %g;", s[i].norm.x, s[i].norm.y, s[i].norm.z);
- printf(" A %g\n", s[i].area);
-
- printf("\tCorners: ");
- for(j=0;j<s[i].p->numVert;j++)
- printf("(%g %g %g) ", s[i].corners[j].x, s[i].corners[j].y,
- s[i].corners[j].z);
- printf("\n");
- }
- printf("\t}\n");
- }
-
- /**********************************************************************/
- /* Sample a triangle's centre, and recursively subdivide uniformly */
- /**********************************************************************/
- void Sample_Triangle_Center(tri,s,iter,sample_num)
- Vector tri[4];
- Sampletype s[MAX_SAMPLES];
- int iter;
- int *sample_num;
- {
- int i;
- Vector mid[3];
- Vector corners[3];
- Vector tri_sample;
-
- if (iter >= 0)
- iter--;
- else
- return;
-
- /* Sample center of triangle, store corners of sample */
- if (iter == -1) {
- tri_sample.x = (tri[0].x + tri[1].x + tri[2].x) / 3.0;
- tri_sample.y = (tri[0].y + tri[1].y + tri[2].y) / 3.0;
- tri_sample.z = (tri[0].z + tri[1].z + tri[2].z) / 3.0;
- s[*sample_num].pos = tri_sample;
- for(i=0;i<3;i++)
- s[*sample_num].corners[i] = tri[i];
- (*sample_num)++;
- }
-
- /* Find middle of edges of triangle */
- mid[0] = *vmiddle(&tri[0],&tri[1]);
- mid[1] = *vmiddle(&tri[1],&tri[2]);
- mid[2] = *vmiddle(&tri[2],&tri[0]);
-
- /* Recursively sample - check only triangles not checked before */
- corners[0] = tri[0]; corners[1] = mid[0]; corners[2] = mid[2];
- Sample_Triangle_Center(corners,s,iter,sample_num);
-
- corners[0] = mid[0]; corners[1] = tri[1]; corners[2] = mid[1];
- Sample_Triangle_Center(corners,s,iter,sample_num);
-
- corners[0] = mid[2]; corners[1] = mid[0]; corners[2] = mid[1];
- Sample_Triangle_Center(corners,s,iter,sample_num);
-
- corners[0] = mid[2]; corners[1] = mid[1]; corners[2] = tri[2];
- Sample_Triangle_Center(corners,s,iter,sample_num);
-
- }
-
- /**********************************************************************/
- /* Sample subdivided triangle */
- /**********************************************************************/
- void Sample_Triangle(tri,s,num_samples,sample_type, corners, area, normal)
- Polygon *tri;
- Sampletype s[MAX_SAMPLES];
- int num_samples;
- int sample_type;
- Vector corners[MAX_PATCH_VTX];
- double area;
- Vector normal;
- {
- int i;
- int sample_num = 0;
- int iter;
- double result;
-
- /* Store rest of info first */
- for(i=0;i<num_samples;i++) {
- s[sample_num].p = tri;
- s[sample_num].norm = normal;
- s[sample_num++].area = area / num_samples;
- }
-
- /* Find sample positions, by recursively subdividing the triangle for
- "iter" number of iterations */
- iter = 0; result = num_samples / 4.0;
- while (result >= 1.0) {
- iter++;
- result /= 4.0;
- }
- sample_num = 0;
- Sample_Triangle_Center(corners,s,iter,&sample_num);
- }
-
- /**********************************************************************/
- /* Sample quadralateral */
- /**********************************************************************/
- void Sample_Quad(quad,s,num_samples,sample_type, corners, area, normal)
- Polygon *quad;
- Sampletype s[MAX_SAMPLES];
- int num_samples;
- int sample_type;
- Vector corners[MAX_PATCH_VTX];
- double area;
- Vector normal;
- {
- int i,j;
- double u,v, du, dv;
- double jitter_u, jitter_v;
- Vector tmp;
- int nu, nv;
- int sample_num = 0;
-
- for(i=0;i<MAX_PATCH_VTX;i++)
- corners[i] = quad->vert[i]->pos;
-
- /* Set grid subdivision */
- nv = nu = CEILING(sqrt((double)num_samples));
- dv = du = 1.0 / (double) nu;
-
- for(i=0,u=du/2.0; i<nu; i++, u+=du) {
- for(j=0,v=dv/2.0; j<nv; j++, v+=dv, sample_num++) {
- UVToXYZ(corners, u, v, &tmp);
- s[sample_num].pos = tmp;
- UVToXYZ(corners, u-du/2.0, v-dv/2.0, &tmp);
- s[sample_num].corners[0] = tmp;
- UVToXYZ(corners, u+du/2.0, v-dv/2.0, &tmp);
- s[sample_num].corners[1] = tmp;
- UVToXYZ(corners, u+du/2.0, v+dv/2.0, &tmp);
- s[sample_num].corners[2] = tmp;
- UVToXYZ(corners, u-du/2.0, v+dv/2.0, &tmp);
- s[sample_num].corners[3] = tmp;
- s[sample_num].p = quad;
- s[sample_num].norm = normal;
- s[sample_num].area = area / num_samples;
- }
- }
- }
-
- #define MIN_SOURCE_UNSHOT 0.1
- #define MAX_SOURCE_UNSHOT 0.5
- #define USE_NEW 1
- /**********************************************************************/
- /* Routine to adjust number of samples to generate based on given */
- /* criteria. Currently adjust # of rays depending on: */
- /* - level of subdivsion of element. */
- /* - closeness and area of light wrt receiver (i.e. what solid */
- /* angle does it subtend?) */
- /* - total radiosity of source < tolerance */
- /**********************************************************************/
- int Adjusted_NumSamples(p)
- Polygon *p;
- {
- int i;
- int num_samps, scale;
- int sample_weight; /* 0 = 1 sample, 1 = 4 samples, 2 = sixteen samples */
-
- #ifdef USE_NEW
- if (FF_Options.num_samples == 16)
- sample_weight = 2;
- else if (FF_Options.num_samples == 4)
- sample_weight = 1;
- else
- sample_weight = 0;
-
- /* Adjust based on source radiosity */
- for (i=0;i<MAX_SPECTRA_SAMPLES;i++)
- if (p->unshot_B.samples[i] < MIN_SOURCE_UNSHOT)
- sample_weight--;
-
- /* Adjust based on solid angle source subtends receiver */
- /* (Not implemented) */
-
- /* Adjust based on receiver size -- new */
- if (p->level > 0) {
- scale = (int) Power(4.0,(double)p->level);
- if (scale >= FF_Options.num_samples)
- sample_weight = 0;
- else
- sample_weight -= p->level;
- }
-
- num_samps = 1;
- if (sample_weight < 0) sample_weight = 0;
- else if (sample_weight > 2) sample_weight = 2;
- for (i=1;i<sample_weight;i++)
- num_samps = num_samps * 4;
-
- if (Option.statistics) {
- if (Option.device == PRINT)
- printf("\tAdjusted number samples = %d\n", num_samps);
- else
- fprintf(Option.StatFile,"\tAdjusted number samples = %d\n", num_samps);
- }
-
- #else
- /* Adjust based on receiver size -- old */
- if (p->level > 0) {
- scale = (int) Power(4.0,(double)p->level);
- if (scale >= FF_Options.num_samples)
- num_samps = 1;
- else
- num_samps = FF_Options.num_samples / scale;
- } else
- num_samps = FF_Options.num_samples;
-
- #endif
-
- return num_samps;
- }
-
- /**********************************************************************/
- /* Generate samples (s) on a patch (p) */
- /**********************************************************************/
- int ff_Generate_Patch_Samples(p,s,corners,area,normal)
- Polygon *p;
- Sampletype s[MAX_SAMPLES];
- Vector corners[MAX_PATCH_VTX];
- double area;
- Vector normal;
- {
- int num_samples;
- int i;
-
- if (FF_Options.fftype == ANALYTIC_FF)
- num_samples = DEFAULT_ASAMPLES;
- else {
- if (FF_Options.varying_numsamps)
- num_samples = Adjusted_NumSamples(p);
- else
- num_samples = FF_Options.num_samples;
- }
-
- switch (FF_Options.sampling_type) {
-
- case UNITEST: /* Test only */
-
- for (i=0;i<num_samples;i++) {
- s[i].p = p;
- s[i].pos = corners[i];
- s[i].norm = normal;
- s[i].area = area / num_samples;
- }
- break;
-
- case UNIFORM: /* Sample centres of grid patch */
-
- if (p->class == PATCH)
- Sample_Quad(p,s,num_samples,UNIFORM,corners,area,normal);
- else if (p->class == TRIANGLE)
- Sample_Triangle(p,s,num_samples,UNIFORM,corners,area,normal);
- break;
-
- case JITTERED: /* Sample with centers jittered */
-
- if (p->class == PATCH)
- Sample_Quad(p,s,num_samples,JITTERED,corners,area,normal);
- else if (p->class == TRIANGLE)
- Sample_Triangle(p,s,num_samples,JITTERED,corners,area,normal);
- break;
-
- default:
- fprintf(stderr,"%s: Unknown sampling type %d\n", ProgName,
- FF_Options.sampling_type);
- exit(1);
- }
- return (num_samples);
- }
-
-
- /**********************************************************************/
- /* Test if a reciever vertex is on the plane of the src poly */
- /**********************************************************************/
- int Patches_Abut(src,rec)
- Polygon *src, *rec;
- {
- int i;
- Vector rv, sv, sn, ray_dir;
- double cos_angle_p;
- int is_perp = FALSE;
- int is_touching = FALSE;
-
- /* Is perpendicular test */
- sn = src->normal[0];
- i = 0;
- while (i<rec->numVert && is_perp == FALSE) {
- sv = src->vert[0]->pos;
- rv = rec->vert[i]->pos;
- ray_dir = *vsub(&sv,&rv);
- norm(&ray_dir);
- cos_angle_p = dot(&sn, vnegate(&ray_dir));
- if (cos_angle_p == 0.0)
- is_perp = TRUE;
- i++;
- }
-
- if (is_perp) {
- i = 0;
- while (i<src->numVert && is_touching == FALSE) {
- sv = src->vert[i]->pos;
- if (vsame(&rv, &sv, DAMN_SMALL)) is_touching = TRUE;
- i++;
- }
- }
- return is_touching;
- }
-
- int FF_Testing = 0; /* Just for testing */
- /**********************************************************************/
- /* Shoot a ray from vertex to sample point on source */
- /* Return intersection distance */
- /**********************************************************************/
- int shoot_ray(ray_orig, ray_dir, s, t)
- Vector ray_orig, ray_dir;
- Sampletype s;
- double *t;
- {
- double tmp;
- Vector normray_dir;
-
- tmp = vlen(&ray_dir); /* Find distance from source to receiver */
- *t = tmp;
- if (FF_Testing) {
- printf("\tShooting from %g,%g,%g to %g,%g,%g ",
- ray_orig.x, ray_orig.y, ray_orig.z,
- ray_dir.x, ray_dir.y, ray_dir.z);
- printf("at pos %g %g %g. t = %g\n", s.pos.x, s.pos.y, s.pos.z, *t);
- }
-
- /* Find out if ray hit any object before reaching sample point on
- source */
- if (Option.visibility == FORM_FACTOR) {
- normray_dir = ray_dir;
- norm(&normray_dir);
- if (HitObject(ray_orig, normray_dir, *t))
- return 0;
- else
- return 1;
- } else
- return 1;
- }
-
- /*====================================================================*/
- /* Analytically integrated form-factor from [BAUM90], using contour */
- /* integration. */
- /*====================================================================*/
- double ff_da_analytic(pptr, from, corners, pnorm)
- Polygon *pptr; /* Source polygon */
- Vector *from; /* Receiver vertex */
- Vector *pnorm; /* Receiver normal */
- Vector corners[MAX_PATCH_VTX]; /* Source sample corners */
- {
- int i, ii;
- double dff;
- Vector R[MAX_PATCH_VTX];
- Vector Tau[MAX_PATCH_VTX];
- Vector direction;
- double corner_angle;
- double cos_corner_angle;
-
- /* Set receiver normal, and rays from receiver
- position to corners of source */
- for(i=0;i<(pptr->numVert);i++) {
- R[i] = *vsub(&corners[i], from);
- norm(&R[i]);
- }
-
- /* Calculate ff by numerically integrating */
- dff = 0.0;
- for(i=0;i<pptr->numVert;i++) {
- ii = (i + 1) % pptr->numVert;
- cos_corner_angle = dot(&R[i], &R[ii]);
- corner_angle = acos(cos_corner_angle);
- direction = cross(&R[i], &R[ii]);
- norm(&direction);
- Tau[i] = *vscalar(corner_angle, &direction);
- dff += fabs(dot(pnorm, &Tau[i]));
- }
-
- dff = dff / (2.0 * PI);
- return(dff);
- }
-
- #define MAX_SRC_TO_RECVTX_ENERGY 5.0
- /*====================================================================*/
- /* Ray tracing ff -- circular disc approximation by [Wallace89] */
- /* 1) Assume uniform weighted area per sample */
- /* 2) Uniform or jittered sample points on area samples */
- /*====================================================================*/
- double ff_da_disc(v,n,p,samples,num_samples)
- Vector v, n; /* Vertex and normal to sample from */
- Polygon *p; /* Polygon to be sampled */
- Sampletype samples[MAX_SAMPLES]; /* Samples on source */
- int num_samples; /* Number of source samples */
- {
- int i;
- double ff, cos_angle_v, cos_angle_p, t, dff, w; /* for ff calc */
- Vector ray_dir; /* Direction of ray from vtx */
- Vector norm_ray_dir; /* Normalized ray direction */
-
- /* Calculate delta form-factor from each sample */
- ff = 0.0;
- for (i=0;i<num_samples;i++) {
- ray_dir = *vsub(&(samples[i].pos), &v);
- norm_ray_dir = ray_dir;
- norm(&norm_ray_dir);
- w = samples[i].area;
- if (shoot_ray(v, ray_dir, samples[i], &t)) {
- cos_angle_v = dot(&n, &norm_ray_dir);
- cos_angle_p = dot(&(samples[i].norm), vnegate(&norm_ray_dir));
- if (cos_angle_p == 0.0) cos_angle_p = cos(DTOR * 90.0);
- dff = (cos_angle_v * cos_angle_p) / ((M_PI * t*t) + samples[i].area);
-
- /* Take area weighted average of samples as form factor */
- dff = dff * w;
- ff += dff;
- }
- }
- return(ff);
- }
-
- /*====================================================================*/
- /* Ray tracing ff -- elliptical disc approximation [Siegal81] */
- /*====================================================================*/
- double ff_da_ellipse(v,n,p,samples,num_samples)
- Vector v, n; /* Vertex and normal to sample from */
- Polygon *p; /* Polygon to be sampled */
- Sampletype samples[MAX_SAMPLES]; /* Samples on source */
- int num_samples; /* Number of source samples */
- {
- int i;
- double ff, cos_angle_v, cos_angle_p, t, dff, w; /* for ff calc */
- Vector ray_dir; /* Direction of ray from vtx */
- Vector norm_ray_dir; /* Normalized ray direction */
- double a,b;
-
- /* Calculate delta form-factor from each sample */
- ff = 0.0;
- for (i=0;i<num_samples;i++) {
- ray_dir = *vsub(&(samples[i].pos), &v);
- a = vlen(vsub(&samples[i].pos,
- vmiddle(&samples[i].corners[2], &samples[i].corners[1])));
- if (p->class == TRIANGLE)
- b = vlen(vsub(&samples[i].pos, &samples[i].corners[2]));
- else
- b = vlen(vsub(&samples[i].pos,
- vmiddle(&samples[i].corners[3], &samples[i].corners[2])));
-
- norm_ray_dir = ray_dir;
- norm(&norm_ray_dir);
- w = samples[i].area;
- if (shoot_ray(v, ray_dir, samples[i], &t)) {
- cos_angle_v = dot(&n, &norm_ray_dir);
- cos_angle_p = dot(&(samples[i].norm), vnegate(&norm_ray_dir));
- if (cos_angle_p == 0.0) cos_angle_p = cos(DTOR * 90.0);
-
- if (a == b) /* Is a circle */
- dff = (cos_angle_v * cos_angle_p) / ((M_PI * t*t) + samples[i].area);
- else /* Is an ellipse */
- dff = (cos_angle_v * cos_angle_p) /
- (M_PI * sqrt( (t*t+a*a) * (t*t+b*b) ) );
- dff = dff * w;
-
- /* Take area weighted average of samples as form factor */
- ff += dff;
- }
- }
- return(ff);
- }
-
- /**********************************************************************/
- /* Find form factors between all element vertices of receiver and all */
- /* source samples. */
- /**********************************************************************/
- double ff_patches(src,rec,ff_rs_vtx,
- num_src_samples, src_samples,
- corners)
- Polygon *src; /* Source */
- Polygon *rec; /* Receiver */
- double ff_rs_vtx[MAX_PATCH_VTX]; /* Receiver form factors */
- int num_src_samples; /* Number of source samples */
- Sampletype src_samples[MAX_SAMPLES]; /* Source samples */
- Vector corners[MAX_PATCH_VTX]; /* Corners of source */
- {
- int i;
- double ff_rs; /* Form factor total */
- double element_ff;
- Vector element_pos, element_norm;
- Vector rec_corners[MAX_PATCH_VTX]; /* Samples for analytic */
- Sampletype rec_samples[MAX_SAMPLES];
- int num_rec_samples;
-
- float ff_start, ff_end;
-
- ff_rs = 0.0;
- ff_start = Cpu_Time(&tstats.utime, &tstats.stime);
-
- if (FF_Options.fftype == NUMERICAL_FF) {
-
- /* Check from all corners of receiver */
- for(i=0;i<rec->numVert;i++) {
- ff_rs_vtx[i] = 0.0;
- element_pos = rec->vert[i]->pos;
- element_norm = rec->normal[0];
-
- /* Check perpendicular condition here. If so sample from
- centers as well. N/F */
- /* if (dot(&element_norm, &src_samples[0].norm) == 0) { */
-
- if (FF_Options.sample_shape == DISC_FF)
- element_ff = ff_da_disc(element_pos, element_norm,
- src, src_samples, num_src_samples);
- else
- element_ff = ff_da_ellipse(element_pos, element_norm,
- src, src_samples, num_src_samples);
- if (element_ff > 0.0) {
- ff_rs += element_ff; /* Sum total ff */
- ff_rs_vtx[i] = element_ff; /* Store vertex ff */
- }
- }
- }
-
- else if (FF_Options.fftype == ANALYTIC_FF) {
-
- /* Check from centres of sample areas on receiver */
- for(i=0;i<rec->numVert;i++)
- rec_corners[i] = rec->vert[i]->pos;
- num_rec_samples = ff_Generate_Patch_Samples(rec,rec_samples, rec_corners,
- rec->area, rec->normal[0]);
- for (i=0;i<num_rec_samples;i++) {
- ff_rs_vtx[i] = ff_da_analytic(src, &rec_samples[i].pos, corners,
- &rec->normal[0]);
- ff_rs_vtx[i] /= (double)num_rec_samples;
- ff_rs += ff_rs_vtx[i];
- }
- }
-
- ff_end = Cpu_Time(&tstats.utime, &tstats.stime);
- tstats.avg_ff += (ff_end - ff_start);
-
- if (Option.debug) {
- printf("\t+ Receiver %s%d to source %s%d ff: %g\n\t with vertex ff: ",
- rec->name, rec->id, src->name, src->id,ff_rs);
- for(i=0;i<rec->numVert;i++) printf("%g ",ff_rs_vtx[i]);
- printf("\n");
- }
- return (ff_rs);
- }
-
- /*====================================================================*/
- /* Code for form-factor refine from [Hanrahan91]. Currently not used. */
- /*====================================================================*/
- /**********************************************************************/
- /* Create new polygon for poly list of poly, update back of list */
- /**********************************************************************/
- void LinkPoly_ToPoly(to_poly, link_poly, ff_to_link)
- Polygon *to_poly, *link_poly;
- double ff_to_link;
- {
- PolyList *pl;
-
- pl = (PolyList *) malloc(sizeof(PolyList));
- pl->patch = link_poly;
- pl->next = (PolyList *)0;
-
- if (to_poly->polyhead.num_polys == 0) { /* No links with any polys yet */
- to_poly->Links = pl;
- to_poly->polyhead.front = to_poly->polyhead.back = to_poly->Links;
- } else { /* Add to end of list */
- to_poly->polyhead.back->next = pl;
- to_poly->polyhead.back = pl;
- }
- to_poly->polyhead.num_polys++;
- }
-
- /**********************************************************************/
- /* Polygon p can "see" q and q can "see" p */
- /**********************************************************************/
- void ff_Link_Patches(p,q, ff_pq, ff_qp)
- Polygon *p, *q;
- double ff_pq, ff_qp;
- {
- if (Option.debug)
- printf("\tLinking polygon %s%d and poly %s%d.\n",
- p->name, p->id, q->name, q->id);
- LinkPoly_ToPoly(p,q, ff_pq);
- LinkPoly_ToPoly(q,p, ff_qp);
- }
-
- /**********************************************************************/
- /* Perform BF refinement on 2 patches */
- /**********************************************************************/
- void ff_BF_Refine(src,rec)
- Polygon *src, *rec;
- {
- int i;
- double ff_rs, ff_sr;
- double ff_difference;
- double subdiv_src_area, subdiv_rec_area;
- double ff_rs_vtx[MAX_PATCH_VTX];
- double ff_sr_vtx[MAX_PATCH_VTX];
-
- int num_src_samples;
- int num_rec_samples;
- Sampletype src_samples[MAX_SAMPLES];
- Sampletype rec_samples[MAX_SAMPLES];
- Vector src_corners[MAX_PATCH_VTX];
- Vector rec_corners[MAX_PATCH_VTX];
-
- /* Find corners of source and receiver, and generate sample
- points on source and receiver patch */
- for(i=0;i<src->numVert;i++) src_corners[i] = src->vert[i]->pos;
- num_src_samples = ff_Generate_Patch_Samples(src,src_samples,
- src_corners, src->area,
- src->normal[0]);
- for(i=0;i<rec->numVert;i++) rec_corners[i] = rec->vert[i]->pos;
- num_rec_samples = ff_Generate_Patch_Samples(rec,rec_samples,
- rec_corners, rec->area,
- rec->normal[0]);
-
- /* Find form factors from source to receiver and vice versa */
- ff_sr = ff_patches(src,rec,ff_sr_vtx, num_src_samples,
- src_samples, src_corners);
- ff_rs = ff_patches(rec,src,ff_rs_vtx, num_rec_samples,
- rec_samples, rec_corners);
- ff_difference = fabs(ff_sr - ff_rs);
- subdiv_src_area = src->area / 4.0;
- subdiv_rec_area = rec->area / 4.0;
-
- if ((ff_rs < FF_Options.F_min) && (ff_sr < FF_Options.F_min))
- ff_Link_Patches(src,rec, ff_sr, ff_rs);
- else if (ff_difference > FF_Options.F_diff_poly) {
-
- if (ff_sr > ff_rs) {
- if (subdiv_rec_area > FF_Options.min_element_area) {
- /* Subdivide polygon rec and refine */
- Subdivide_Polygon(rec);
- for (i=0;i<MAX_PATCH_CHILDREN;i++)
- ff_BF_Refine(src,rec->child[i]);
- } else
- ff_Link_Patches(src,rec, ff_sr, ff_rs);
- } else {
- if (subdiv_src_area > FF_Options.min_element_area) {
- /* Subdivide polygon src and refine */
- Subdivide_Polygon(src);
- for (i=0;i<MAX_PATCH_CHILDREN;i++)
- ff_BF_Refine(rec,src->child[i]);
- } else
- ff_Link_Patches(src,rec, ff_sr, ff_rs);
- }
- }
- }
-
-